#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
This...
"""
import sys
import os
import argparse

import cv
import pyexiv2

# Parameters for haar detection
# From the API:
# The default parameters (scale_factor=2, min_neighbors=3, flags=0) are tuned 
# for accurate yet slow object detection. For a faster operation on real video 
# images the settings are: 
# scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING, 
# min_size=<minimum possible face size

min_size = (20, 20)
image_scale = 4
haar_scale = 1.2
min_neighbors = 2
haar_flags = 0

def detect_and_draw(img, cascade):
    # allocate temporary images
    gray = cv.CreateImage((img.width,img.height), 8, 1)
    small_img = cv.CreateImage((cv.Round(img.width / image_scale),
			       cv.Round (img.height / image_scale)), 8, 1)

    # convert color input image to grayscale
    cv.CvtColor(img, gray, cv.CV_BGR2GRAY)

    # scale input image for faster processing
    cv.Resize(gray, small_img, cv.CV_INTER_LINEAR)

    cv.EqualizeHist(small_img, small_img)

    if(cascade):
        t = cv.GetTickCount()
        faces = cv.HaarDetectObjects(small_img, cascade, cv.CreateMemStorage(0),
                                     haar_scale, min_neighbors, haar_flags, min_size)
        t = cv.GetTickCount() - t
        print "detection time = %gms" % (t/(cv.GetTickFrequency()*1000.))
        faces2 = [] # The results scaled back to original image size
        if faces:
            for ((x, y, w, h), n) in faces:
                faces2.append(((x*image_scale, y*image_scale, w*image_scale, h*image_scale), n))
                # the input to cv.HaarDetectObjects was resized, so scale the 
                # bounding box of each face and convert it to two CvPoints
                pt1 = (int(x * image_scale), int(y * image_scale))
                pt2 = (int((x + w) * image_scale), int((y + h) * image_scale))
                cv.Rectangle(img, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0)
        return faces2


def loadImage(fname):
    """ A load image facility that supports raw-images via exiv2 """

    basename, ext = os.path.splitext(fname)
    ext = ext.lstrip('.').lower()

    RAW_EXTENSIONS = ['nef', 'cr2']
    if (ext in RAW_EXTENSIONS):
        # A raw image...
        metadata = pyexiv2.ImageMetadata(fname)
        metadata.read()
        pre = metadata.previews[-1] # The preview image which is going to be extracted...
        tmppath = '/dev/shm/image-analysis'
        pre.write_to_file(tmppath)
        return cv.LoadImage(tmppath + pre.extension, 1)
    else:
        # A 'normal' image...
        return cv.LoadImage(fname, 1)


if __name__ == '__main__':
    thisdir = os.path.dirname(os.path.realpath( __file__ ))

    parser = argparse.ArgumentParser(description='photodb', epilog="Author: Juuso Räsänen")
    parser.add_argument('fname', nargs='*', default='.', help="fname")
    parser.add_argument('-debug', '-d', action='store_true', help='Print some additional debug info')
    parser.add_argument('-show', action='store_true', help='Show the output image in the end')
    parser.add_argument('-face', action='store_true', help='Perform face detection')
    parser.add_argument('-avg', action='store_true', help='Average and standard deviation')
    parser.add_argument('-cascade', default=os.path.join(thisdir,'haarcascade_frontalface_alt.xml'), help='Haar Cascade to be used in face detection')
    parser.add_argument('-save', action='store_true', help='Save the results in the image metadata')

    args = parser.parse_args()
    cascade = cv.Load(args.cascade)

    if args.save:
        pyexiv2.xmp.register_namespace("http://www.iki.fi/juuso.rasanen/",'photodb')

    for fname in args.fname:
        img = loadImage(fname)

        # Read the metadata if needed
        if args.save:
            metadata = pyexiv2.ImageMetadata(fname)
            metadata.read()


        if args.avg:
            print "avg=" + str(cv.AvgSdv(img))

        if args.face:
            faces = str(detect_and_draw(img, cascade))
            print "faces=" + faces
            if args.save:
                metadata['Xmp.photodb.faces'] = faces


        # Write the results into the metadata if needed
        if args.save:
            metadata.write()


    if args.show:
        ar = float(img.width) / float(img.height)
        small_img = cv.CreateImage((cv.Round(800),
			           cv.Round (800/ar)), 8, img.nChannels)
        cv.Resize(img, small_img, cv.CV_INTER_LINEAR)

        cv.NamedWindow("result", 1)
        cv.ShowImage("result", small_img)
        cv.WaitKey(0)

    cv.DestroyWindow("result")
